<?php
/**
 * Eka Framework 0.3.0
 *
 * @copyright Copyright (c) 2008 Alexey Yu. Chuprina <656b61@gmail.com> (http://php-eka.googlecode.com)
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 *
 * @version $Id$
 */

/**
 * Eka_File
 *
 * @package File
 */
class Eka_File
{
	const TYPE_UNKNOWN = 0;
	const TYPE_IMAGE = 1;
	const TYPE_MUSIC = 2;
	const TYPE_VIDEO = 3;

	static protected $magicFile = '/usr/share/misc/magic';
	static protected $cmdFfmpeg = 'ffmpeg';
	static protected $cmdFile = 'file';

	/**
	 * Factory
	 *
	 * @param string $file
	 * @return Eka_File
	 */
	static public function factory($file)
	{
		switch (self::getFileType($file)) {
			case self::TYPE_IMAGE:
				include_once 'Eka/File/Image.php';
				return new Eka_File_Image($file);
			case self::TYPE_VIDEO:
				include_once 'Eka/File/Video.php';
				return new Eka_File_Video($file);
			case self::TYPE_MUSIC:
				include_once 'Eka/File/Music.php';
				return new Eka_File_Music($file);
			default:
				return new self($file);
		}
	}

	static public function setMagicFile($file)
	{
		self::$magicFile = $file;
	}

	static public function setCmdFfmpeg($path)
	{
		self::$cmdFfmpeg = escapeshellcmd($path);
	}

	static public function setCmdFile($path)
	{
		self::$cmdFile = escapeshellcmd($path);
	}

	/**
	 * Determine the type of file
	 *
	 * Used Fileinfo Functions
	 *
	 * @param string $file
	 * @return integer self::TYPE_*
	 */
	static public function getFileType($file)
	{
		if (function_exists('finfo_file')) {
			$mimeType = trim(finfo_file(finfo_open(FILEINFO_MIME, self::$magicFile), $file));
		} else {
			$mimeType = trim(exec(self::$cmdFile.' -b -i '.escapeshellarg($file)));
		}
		switch ($mimeType) {
			# Image
			case 'image/jpeg':
			case 'image/pjpeg':
			case 'image/pjpg':
			case 'image/jpg':
			case 'image/png':
			case 'image/x-png':
			case 'image/gif':
				return self::TYPE_IMAGE;

			# Music
			case 'audio/mpeg':
				return self::TYPE_MUSIC;

			# Video
			case 'video/x-msvideo': #avi- mozilla
			case 'video/avi': #avi - EI
			case 'video/x-ms-wmv': #wmv
			case 'video/mpeg': #mpeg
			case 'video/quicktime': #mov
			case 'video/3gpp': #3gp
			case 'application/octet-stream': #flv or wmv
				return self::TYPE_VIDEO;

			# Unknown
			default:
				return self::TYPE_UNKNOWN;
		}
	}

	############################################################################

	/**
	 * File type
	 *
	 * @var integer
	 */
	protected $type = self::TYPE_UNKNOWN;

	/**
	 * Full file path
	 *
	 * @var string
	 */
	protected $file = null;

	/**
	 * Constructor
	 *
	 * @param string $file
	 */
	public function __construct($file)
	{
		$this->file = realpath($file);
		if (!is_file($this->file)) {
			include_once 'Eka/File/Exception.php';
			throw new Eka_File_Exception("File '$file' not found");
		}
	}

	/**
	 * Return file type
	 *
	 * @return integer self::TYPE_*
	 */
	public function getType()
	{
		return $this->type;
	}

	/**
	 * Retrun full file path
	 *
	 * @return string
	 */
	public function getFile()
	{
		return $this->file;
	}

	/**
	 * Return path to this file directory
	 *
	 * @return string
	 */
	public function getDirectory()
	{
		return pathinfo($this->file, PATHINFO_DIRNAME);
	}

	/**
	 * Return file name
	 *
	 * @return string
	 */
	public function getName()
	{
		return pathinfo($this->file, PATHINFO_BASENAME);
	}

	/**
	 * Return file name without extension
	 *
	 * @return string
	 */
	public function getBaseName()
	{
		$info = pathinfo($this->file);
		if ($info['filename'] == '') {
			return $info['basename'];
		}
		return $info['filename'];
	}

	/**
	 * Return file extension
	 *
	 * @return string
	 */
	public function getExtension()
	{
		$info = pathinfo($this->file);
		if (!isset($info['extension']) || $info['filename'] == '') {
			return null;
		}
		return $info['extension'];
	}

	/**
	 * Return file size
	 *
	 * @return integer
	 */
	public function getSize()
	{
		return filesize($this->file);
	}

	/**
	 * Change file extension
	 *
	 * @param string $extension
	 */
	public function setExtension($extension)
	{
		$extension = (string)$extension;
		#@todo Как быть если такой файл уже есть?
		#@todo Добавить проверку на успешность изменения разширения
		if ($extension !== '') $extension = '.' . $extension;
		$newPath = $this->getDirectory() . '/' . $this->getBaseName() . $extension;
		rename($this->file, $newPath);
		$this->file = $newPath;
	}

	/**
	 * Rename file
	 *
	 * Меняеть только название файла, директория не меняется
	 *
	 * @param string $name
	 */
	public function rename($name)
	{
		#@todo Как быть если такой файл уже есть?
		#@todo Добавить проверку на валидность нового имени
		#@todo Добавить проверку на успешность переименования
		$newFile = $this->getDirectory() . '/' . $name;
		rename($this->file, $newFile);
		$this->file = $newFile;
	}

	/**
	 * Move file to directory
	 *
	 * Необходимо указывать именно путь дериктории в которую нужно переместить
	 * файл, имя файла остается тоже что и есть.
	 * Для переименования смотри метод {@link rename()}
	 *
	 * @param string $directory
	 */
	public function move($directory)
	{
		#@todo Добавить проверку на успешность перемещения
		$newFile = $directory . '/' . $this->getName();
		rename($this->file, $newFile);
		$this->file = $newFile;
	}

	/**
	 * Copy file
	 *
	 * @param string $file Full new file path
	 * @param integer $mode
	 * @return Eka_File
	 */
	public function copy($file, $mode = null)
	{
		#@todo Добавить проверку на успешность копирования
		copy($this->file, $file);
		$newFile = self::factory($file);
		if ($mode) {
			$newFile->chmod($mode);
		}
		return $newFile;
	}

	/**
	 * Changes file mode
	 *
	 * @param integer $mode
	 */
	public function chmod($mode)
	{
		#@todo Добавить проверку на успешность изменения прав доступа
		chmod($this->file, $mode);
	}

	/**
	 * Delete file
	 *
	 * @param integer $mode
	 */
	public function delete()
	{
		#@todo Добавить проверку на успешность
		unlink($this->file);
	}

	/**
	 * @return Eka_File
	 */
	public function toType()
	{
		return self::factory($this->file);
	}
}
